package com.xiyoukt.springboot.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

// 定义切面
//@Aspect
//@Component
public class LogAspect {

    private static Logger log = LoggerFactory.getLogger(LogAspect.class);

    // 定义切点，拦截那些方法，常用的有两种方式：execution和@annotation
//    @Pointcut("execution(public * com.xiyoukt.springboot.controller.*.*(..))")
    @Pointcut("@annotation(com.xiyoukt.springboot.annotation.TestAnnotation)")
    public void logPoint(){}

    // 前置通知，被拦截方法执行前调用
//    @Before("logPoint()")
//    public void before(JoinPoint joinPoint){
//        ServletRequestAttributes requestAttributes =
//                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        HttpServletRequest request = requestAttributes.getRequest();
//        log.info("URL: {}", request.getRequestURL());
//        log.info("METHOD: {}", request.getMethod());
//        log.info("IP: {}", request.getRemoteAddr());
//        log.info("CLAAS_METHOD: {}.{}", joinPoint.getSignature().getDeclaringTypeName(),
//                joinPoint.getSignature().getName()) ;
//        log.info("ARGS: {}", joinPoint.getArgs());
//    }
//
//    // 后置通知，被拦截方法执行后调用
//    @After("logPoint()")
//    public void after(JoinPoint joinPoint){
//        log.info("CLAAS_METHOD: {}.{}", joinPoint.getSignature().getDeclaringTypeName(),
//                joinPoint.getSignature().getName()) ;
//    }
//
//    // 异常通知，被拦截放啊抛出异常后调用
//    @AfterThrowing(value = "logPoint()", throwing = "throwable")
//    public void afterThrowing(JoinPoint joinPoint, Throwable throwable){
//        log.info("CLAAS_METHOD: {}.{}", joinPoint.getSignature().getDeclaringTypeName(),
//                joinPoint.getSignature().getName()) ;
//        log.error("error: ", throwable);
//    }
//
//    // 最终通知，被拦截方法返回数据后调用
//    @AfterReturning(value = "logPoint()", returning = "ret")
//    public void afterReturning(JoinPoint joinPoint, Object ret){
//        log.info("CLAAS_METHOD: {}.{}", joinPoint.getSignature().getDeclaringTypeName(),
//                joinPoint.getSignature().getName()) ;
//        log.info("返回值: {}", ret);
//    }

    @Around("logPoint()")
    public Object around(ProceedingJoinPoint joinPoint){
        // 在被拦截方法前调用
        ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        log.info("URL: {}", request.getRequestURL());
        log.info("METHOD: {}", request.getMethod());
        log.info("IP: {}", request.getRemoteAddr());
        log.info("CLAAS_METHOD: {}.{}", joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName()) ;
        log.info("ARGS: {}", joinPoint.getArgs());
        Object proceed = null;
        try {
            // 调用被拦截方法
            proceed = joinPoint.proceed();
            // 在被拦截方法返回数据后调用
            log.info("返回数据: {}", proceed);
        } catch (Throwable throwable) {
            // 在被拦截方法抛出异常后调用
//            throwable.printStackTrace();
            log.error("error", throwable);
        }
        // 环绕通知，必须返回数据
        return proceed;
    }

}
